package com.abc.example.service.impl;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.github.pagehelper.PageInfo;
import io.gitee.shengzheng1999.esbcommon.common.impexp.BaseExportObj;
import io.gitee.shengzheng1999.esbcommon.common.impexp.BaseImportObj;
import io.gitee.shengzheng1999.esbcommon.common.impexp.ExcelExportHandler;
import io.gitee.shengzheng1999.esbcommon.common.impexp.ExcelImportHandler;
import io.gitee.shengzheng1999.esbcommon.common.impexp.ImpExpFieldDef;
import io.gitee.shengzheng1999.esbcommon.common.utils.FileUtil;
import io.gitee.shengzheng1999.esbcommon.common.utils.LogUtil;
import io.gitee.shengzheng1999.esbcommon.common.utils.Md5Util;
import io.gitee.shengzheng1999.esbcommon.common.utils.ObjListUtil;
import io.gitee.shengzheng1999.esbcommon.common.utils.ReflectUtil;
import io.gitee.shengzheng1999.esbcommon.common.utils.TimeUtil;
import io.gitee.shengzheng1999.esbcommon.common.utils.Utility;
import io.gitee.shengzheng1999.esbcommon.common.utils.ValidateUtil;
import io.gitee.shengzheng1999.esbcommon.entity.SysParameter;
import com.abc.example.common.constants.Constants;
import com.abc.example.config.UploadConfig;
import com.abc.example.dao.UserDao;
import com.abc.example.entity.Orgnization;
import com.abc.example.entity.User;
import com.abc.example.enumeration.EDeleteFlag;
import com.abc.example.enumeration.EIdType;   
import com.abc.example.enumeration.ESex;
import com.abc.example.enumeration.EUserType;
import com.abc.example.exception.BaseException;
import com.abc.example.exception.ExceptionCodes;
import com.abc.example.service.BaseService;
import com.abc.example.service.DataRightsService;
import com.abc.example.service.IdCheckService;
import com.abc.example.service.SysParameterService;
import com.abc.example.service.TableCodeConfigService;
import com.abc.example.service.UserManService;


/**
 * @className	: UserManServiceImpl
 * @description	: 用户对象管理服务实现类
 * @summary		: 
 * @history		:
 * ------------------------------------------------------------------------------
 * date			version		modifier		remarks
 * ------------------------------------------------------------------------------
 * 2023/05/17	1.0.0		sheng.zheng		初版
 *
 */
@SuppressWarnings({ "unchecked", "unused" })
@Service
public class UserManServiceImpl extends BaseService implements UserManService{
	// 用户对象数据访问类对象
	@Autowired
	private UserDao userDao;

    // 文件上传配置类对象
    @Autowired
    private UploadConfig uploadConfig;

    // 对象ID检查服务类对象
	@Autowired
	private IdCheckService ics;   
	
	// 数据权限服务类对象
	@Autowired
	private DataRightsService drs;

	// 全局ID服务类对象
	@Autowired
	private TableCodeConfigService tccs;
    
    // 系统参数服务类对象
	@Autowired
	private SysParameterService sps;

	// 新增必选字段集
	private String[] mandatoryFieldList = new String[]{"userName","password","userType","orgId"};

	// 修改不可编辑字段集
	private String[] uneditFieldList =  new String[]{"password","salt","deleteFlag"};


	/**
	 * @methodName		: addItem
	 * @description		: 新增一个用户对象
	 * @remark		    : 参见接口类方法说明
	 * @history			:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	@Override
	public Map<String,Object> addItem(HttpServletRequest request, User item) {
		// 输入参数校验
		checkValidForParams(request, "addItem", item);

        // 检查参照ID的有效性
        Integer orgId = item.getOrgId();
        Orgnization orgnization = (Orgnization)ics.getObjById("Orgnization",orgId);

        // 检查数据权限
        drs.checkUserDrByOrgId(request, orgId);

        // 检查枚举值
        int userType = item.getUserType().intValue();
        EUserType eUserType = EUserType.getTypeByCode(userType);
        int sex = item.getSex().intValue();
        ESex eSex = ESex.getTypeByCode(sex);

        // 检查唯一性
        String userName = item.getUserName(); 
        String phoneNumber = item.getPhoneNumber(); 
        String idNo = item.getIdNo(); 
        String openId = item.getOpenId(); 
        String woaOpenid = item.getWoaOpenid(); 
        checkUniqueByUserName(userName);
        checkUniqueByPhoneNumber(phoneNumber);
        checkUniqueByIdNo(idNo);
        checkUniqueByOpenId(openId);
        checkUniqueByWoaOpenid(woaOpenid);
        
        // 业务处理
        LocalDateTime current = LocalDateTime.now();
        String salt = TimeUtil.format(current, "yyyy-MM-dd HH:mm:ss");
        // 明文密码加密
        String password = item.getPassword();
        String encyptPassword = Md5Util.plaintPasswdToDbPasswd(password, salt, Constants.TOKEN_KEY);
        item.setSalt(salt);
        item.setPassword(encyptPassword);
        
        Long userId = 0L;
		// 获取全局记录ID
		Long globalRecId = tccs.getTableRecId("exa_users");
        userId = globalRecId;

		// 获取操作人账号
		String operatorName = getUserName(request);

		// 设置信息
		item.setUserId(userId);
		item.setOperatorName(operatorName);
		
		try {
    		// 插入数据
			userDao.insertItem(item);
			
		} catch(Exception e) {
			LogUtil.error(e);
			throw new BaseException(ExceptionCodes.ADD_OBJECT_FAILED,e.getMessage());
		}
		
		// 构造返回值
		Map<String,Object> map = new HashMap<String,Object>();
        map.put("userId", userId.toString());
		
		return map;
	}

	/**
	 * @methodName		: addItems
	 * @description		: 批量新增用户对象
	 * @remark		    : 参见接口类方法说明
	 * @history			:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	@Override
	public Map<String,Object> addItems(HttpServletRequest request, List<User> itemList) { 
		// 输入参数校验
		checkValidForParams(request, "addItems", itemList);
		
		if (itemList.size() == 0) {
			throw new BaseException(ExceptionCodes.ARGUMENTS_IS_EMPTY,"itemList");
		}
		
        // 取出第一个对象数据
        User firstItem = itemList.get(0);

        // 数据有效性检查
        // 为了提高检查的效率，使用字典保存已检查的检查项和相关值
        // 外层key为检查项，内层key为检查项对应的对象数据的相关唯一值，value为任意值，使用整数1
        Map<String,Map<String,Object>> checkListMap = new HashMap<String,Map<String,Object>>();
        Map<String,Object> checkItemMap = null;
        String checkItemName = "";
        String valueKey = "";
        for (User item : itemList){
            // 检查参数一致性
            if (!item.getOrgId().equals(firstItem.getOrgId())){
                throw new BaseException(ExceptionCodes.ARGUMENTS_IS_INCOMPATIBLE,"orgId");
            }

            // 检查参照ID的有效性
            checkItemName = "refId";
            checkItemMap = Utility.getMapItem(checkListMap, checkItemName);
                    
            Integer orgId = item.getOrgId();
            valueKey = orgId.toString();
            if (!checkItemMap.containsKey(valueKey)){
                // 如果该值未检查过，则执行检查，然后将值加入检查项字典
                Orgnization orgnization = (Orgnization)ics.getObjById("Orgnization",orgId);
                checkItemMap.put(valueKey,1);
            }

            // 检查数据权限
            checkItemName = "dr";
            checkItemMap = Utility.getMapItem(checkListMap, checkItemName);
            valueKey = orgId.toString();
            if (!checkItemMap.containsKey(valueKey)){
                drs.checkUserDrByOrgId(request, orgId);
                checkItemMap.put(valueKey,1);
            }

            // 检查枚举值
            checkItemName = "enum";
            checkItemMap = Utility.getMapItem(checkListMap, checkItemName);
            int userType = item.getUserType().intValue();
            valueKey = "EUserType" + "_" + userType;
            if (!checkItemMap.containsKey(valueKey)){
                EUserType eUserType = EUserType.getTypeByCode(userType);
                checkItemMap.put(valueKey,1);
            }            

            checkItemName = "enum";
            checkItemMap = Utility.getMapItem(checkListMap, checkItemName);
            int sex = item.getSex().intValue();
            valueKey = "ESex" + "_" + sex;
            if (!checkItemMap.containsKey(valueKey)){
                ESex eSex = ESex.getTypeByCode(sex);
                checkItemMap.put(valueKey,1);
            }            

            // 检查唯一性
            checkItemName = "unique";
            checkItemMap = Utility.getMapItem(checkListMap, checkItemName);
            valueKey = "userName";
            String userName = item.getUserName(); 
            valueKey += "_" + userName.toString();
            if (!checkItemMap.containsKey(valueKey)){
                checkUniqueByUserName(userName);
                checkItemMap.put(valueKey,1);
            }else{
                // 批量记录中存在唯一键重复的记录
                throw new BaseException(ExceptionCodes.UNIQUE_KEY_FAILED,valueKey);
            }

            valueKey = "phoneNumber";
            String phoneNumber = item.getPhoneNumber(); 
            valueKey += "_" + phoneNumber.toString();
            if (!checkItemMap.containsKey(valueKey)){
                checkUniqueByPhoneNumber(phoneNumber);
                checkItemMap.put(valueKey,1);
            }else{
                // 批量记录中存在唯一键重复的记录
                throw new BaseException(ExceptionCodes.UNIQUE_KEY_FAILED,valueKey);
            }

            valueKey = "idNo";
            String idNo = item.getIdNo(); 
            valueKey += "_" + idNo.toString();
            if (!checkItemMap.containsKey(valueKey)){
                checkUniqueByIdNo(idNo);
                checkItemMap.put(valueKey,1);
            }else{
                // 批量记录中存在唯一键重复的记录
                throw new BaseException(ExceptionCodes.UNIQUE_KEY_FAILED,valueKey);
            }

            valueKey = "openId";
            String openId = item.getOpenId(); 
            valueKey += "_" + openId.toString();
            if (!checkItemMap.containsKey(valueKey)){
                checkUniqueByOpenId(openId);
                checkItemMap.put(valueKey,1);
            }else{
                // 批量记录中存在唯一键重复的记录
                throw new BaseException(ExceptionCodes.UNIQUE_KEY_FAILED,valueKey);
            }

            valueKey = "woaOpenid";
            String woaOpenid = item.getWoaOpenid(); 
            valueKey += "_" + woaOpenid.toString();
            if (!checkItemMap.containsKey(valueKey)){
                checkUniqueByWoaOpenid(woaOpenid);
                checkItemMap.put(valueKey,1);
            }else{
                // 批量记录中存在唯一键重复的记录
                throw new BaseException(ExceptionCodes.UNIQUE_KEY_FAILED,valueKey);
            }

        }

		// 获取操作人账号
		String operatorName = getUserName(request);

        Long userId = 0L;
		// 获取全局记录ID
		Long globalRecId = tccs.getTableRecIds("exa_users", itemList.size());
        userId = globalRecId;

		// 设置信息
		for(int i = 0; i < itemList.size(); i++) {
			User item = itemList.get(i);
            item.setUserId(userId + i);
			item.setOperatorName(operatorName);
		}
		
		try {
    		// 插入数据
            userDao.insertItems(itemList);
			
			 // 可能的数据库一致性处理			
		} catch(Exception e) {
			LogUtil.error(e);
			throw new BaseException(ExceptionCodes.ADD_OBJECT_FAILED,e.getMessage());
		}
		
		// 构造返回值
		Map<String,Object> map = new HashMap<String,Object>();
		map.put("userId", userId);
		
		return map;
	}

	/**
	 * @methodName		: editItem
	 * @description		: 根据key修改一个用户对象
	 * @remark		    : 参见接口类方法说明
	 * @history			:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	@Override
	public void editItem(HttpServletRequest request, Map<String, Object> params) {
		// 输入参数校验
		checkValidForParams(request, "editItem", params);
		
		// 获取对象
        Long userId = Long.valueOf(params.get("userId").toString());

		User oldItem = userDao.selectItemByKey(userId);
		if (oldItem == null) {
            String prompt = "userId=" + userId;
			throw new BaseException(ExceptionCodes.OBJECT_DOES_NOT_EXIST,prompt);
		}
   
        // 检查数据权限
        Integer orgId = oldItem.getOrgId();
        drs.checkUserDrByOrgId(request, orgId);
        // 检查参照ID的有效性
            orgId = (Integer)params.get("orgId");
        if (orgId != null && !oldItem.getOrgId().equals(orgId)){
            Orgnization orgnization = (Orgnization)ics.getObjById("Orgnization",orgId);
        }
            
        // 检查枚举值
        Integer userType = (Integer)params.get("userType");
        if (userType != null){
            EUserType eUserType = EUserType.getTypeByCode(userType);
        }

        Integer sex = (Integer)params.get("sex");
        if (sex != null){
            ESex eSex = ESex.getTypeByCode(sex);
        }

        // 检查唯一性
        String userName = (String)params.get("userName"); 
        if (userName == null){
            userName = oldItem.getUserName();
        }
        String phoneNumber = (String)params.get("phoneNumber"); 
        if (phoneNumber == null){
            phoneNumber = oldItem.getPhoneNumber();
        }
        String idNo = (String)params.get("idNo"); 
        if (idNo == null){
            idNo = oldItem.getIdNo();
        }
        String openId = (String)params.get("openId"); 
        if (openId == null){
            openId = oldItem.getOpenId();
        }
        String woaOpenid = (String)params.get("woaOpenid"); 
        if (woaOpenid == null){
            woaOpenid = oldItem.getWoaOpenid();
        }
        if(!oldItem.getUserName().equals(userName)){
            checkUniqueByUserName(userName);            
        }            
        if(!oldItem.getPhoneNumber().equals(phoneNumber)){
            checkUniqueByPhoneNumber(phoneNumber);            
        }            
        if(!oldItem.getIdNo().equals(idNo)){
            checkUniqueByIdNo(idNo);            
        }            
        if(!oldItem.getOpenId().equals(openId)){
            checkUniqueByOpenId(openId);            
        }            
        if(!oldItem.getWoaOpenid().equals(woaOpenid)){
            checkUniqueByWoaOpenid(woaOpenid);            
        }            

		// 获取操作人账号
		String operatorName = getUserName(request);
		// 设置信息
		params.put("operatorName", operatorName);

        // 移除不可编辑的项
        Utility.removeKeys(params, uneditFieldList);

		try {
		    // 修改数据
			userDao.updateItemByKey(params);
			
			 // 可能的数据库一致性处理			
		} catch(Exception e) {
			LogUtil.error(e);
			throw new BaseException(ExceptionCodes.UPDATE_OBJECT_FAILED,e.getMessage());
		}

	}

	/**
	 * @methodName		: updateItems
	 * @description		: 根据条件批量修改用户对象
	 * @remark		    : 参见接口类方法说明
	 * @history			:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */       
	@Override
	public void updateItems(HttpServletRequest request, Map<String, Object> params) {
		// 输入参数校验
		checkValidForParams(request, "updateItems", params);

        // 获取相关的参数值
        Integer orgId = (Integer)params.get("orgId");
        Integer userType = (Integer)params.get("userType");            
        Integer deleteFlag = (Integer)params.get("deleteFlag");            

        // 检查参照ID的有效性
        if (orgId != null){
            Orgnization orgnization = (Orgnization)ics.getObjById("Orgnization",orgId);
        }
                    
        // 数据权限控制
        List<Integer> orgIdList = drs.getQueryDrList(request,"orgId");
        params.put("orgIdList",orgIdList);
            
	
        // 检查枚举值
        if (userType != null){
            EUserType eUserType = EUserType.getTypeByCode(userType);
        }             
        if (deleteFlag != null){
            EDeleteFlag eDeleteFlag = EDeleteFlag.getTypeByCode(deleteFlag);
        }             

		// 获取操作人账号
		String operatorName = getUserName(request);
		// 设置信息
		params.put("operatorName", operatorName);
		
		try {
    		// 修改数据
			userDao.updateItems(params);
			
			 // 可能的数据库一致性处理			
		} catch(Exception e) {
			LogUtil.error(e);
			throw new BaseException(ExceptionCodes.UPDATE_OBJECT_FAILED,e.getMessage());
		}		
	}    

	/**
	 * @methodName		: deleteItem
	 * @description		: 根据key禁用/启用一个用户对象
	 * @remark		    : 参见接口类方法说明
	 * @history			:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	@Override
	public void deleteItem(HttpServletRequest request, Map<String, Object> params) {
		// 输入参数校验
		checkValidForParams(request, "deleteItem", params);
		
		// 获取对象
        Long userId = Long.valueOf(params.get("userId").toString());

		User oldItem = userDao.selectItemByKey(userId);
		if (oldItem == null) {
            String prompt = "userId=" + userId;
			throw new BaseException(ExceptionCodes.OBJECT_DOES_NOT_EXIST,prompt);
		}
        // 检查数据权限
        Integer orgId = oldItem.getOrgId();
        drs.checkUserDrByOrgId(request, orgId);
		// 检查删除标记
		Integer deleteFlag = (Integer)params.get("deleteFlag");
		if (deleteFlag == null) {
			// 默认为停用
			deleteFlag = EDeleteFlag.dfDeletedE.getCode();
			params.put("deleteFlag", deleteFlag);
		}
		if (oldItem.getDeleteFlag() == deleteFlag.byteValue()) {
			// 不变
			return;
		}

        // 另建字典，防止params携带其它参数
        Map<String, Object> dbParams = new HashMap<String, Object>();
        dbParams.put("userId",userId);
        dbParams.put("deleteFlag",deleteFlag.byteValue());        
		// 获取操作人账号
		String operatorName = getUserName(request);
		// 设置信息
		dbParams.put("operatorName", operatorName);

		try {
    		// 修改数据
			userDao.updateItemByKey(dbParams);
			
			 // 可能的数据库一致性处理			
		} catch(Exception e) {
			LogUtil.error(e);
			throw new BaseException(ExceptionCodes.UPDATE_OBJECT_FAILED,e.getMessage());
		}		
	}

	/**
	 * @methodName		: queryItems
	 * @description		: 根据条件分页查询用户对象列表
	 * @remark		    : 参见接口类方法说明
	 * @history			:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	@Override
	public PageInfo<User> queryItems(HttpServletRequest request,
			 Map<String, Object> params) {
		PageInfo<User> pageInfo = null;
        // 数据权限控制
        List<Integer> orgIdList = drs.getQueryDrList(request,"orgId");
        params.put("orgIdList",orgIdList);
            
		try {
    		// 查询数据
			// 分页处理
			processPageInfo(params);
			// 查询记录
			List<User> itemList = userDao.selectItems(params);
            fillRefValue(itemList);
			// 分页对象
			pageInfo = new PageInfo<User>(itemList);
		} catch(Exception e) {
			LogUtil.error(e);
			throw new BaseException(ExceptionCodes.QUERY_OBJECT_FAILED,e.getMessage());
		}
		
		return pageInfo;
	}

	/**
	 * @methodName		: getItem
	 * @description		: 根据key获取一个用户对象
	 * @remark		    : 参见接口类方法说明
	 * @history			:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	@Override
	public User getItem(HttpServletRequest request, Map<String, Object> params) {
		// 输入参数校验
		checkValidForParams(request, "getItem", params);
		
        Long userId = Long.valueOf(params.get("userId").toString());
		
		try {
			// 查询记录
			User item = userDao.selectItemByKey(userId);
			if (item != null) {
	            // 检查数据权限
	            Integer orgId = item.getOrgId();
	            drs.checkUserDrByOrgId(request, orgId);

	            fillRefValue(item);				
			}
    		return item;
		} catch(Exception e) {
			LogUtil.error(e);
			throw new BaseException(ExceptionCodes.QUERY_OBJECT_FAILED,e.getMessage());
		}
	}

	/**
	 * @methodName		: getItems
	 * @description		: 根据条件查询用户对象列表
	 * @remark		    : 参见接口类方法说明
	 * @history			:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	@Override
	public List<User> getItems(HttpServletRequest request,
			 Map<String, Object> params) {
        // 数据权限控制
        List<Integer> orgIdList = drs.getQueryDrList(request,"orgId");
        params.put("orgIdList",orgIdList);
            
		try {
			// 查询记录
			List<User> itemList = userDao.selectItems(params);
            fillRefValue(itemList);
			return itemList;
		} catch(Exception e) {
			LogUtil.error(e);
			throw new BaseException(ExceptionCodes.QUERY_OBJECT_FAILED,e.getMessage());
		}
	}

	/**
	 * 
	 * @methodName		: updateItems
	 * @description	    : 批量修改用户对象记录，用于内部调用
	 * @remark		    : 参见接口类方法说明
	 * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	public void updateItems(Map<String, Object> params){
		try {
    		// 修改数据
			userDao.updateItems(params);
			
			 // 可能的数据库一致性处理			
		} catch(Exception e) {
			LogUtil.error(e);
			throw new BaseException(ExceptionCodes.UPDATE_OBJECT_FAILED,e.getMessage());
		}		
    }

	/**
	 * 
	 * @methodName		: flushItem
	 * @description	    : 对象存在则修改，否则新增，用于内部调用
	 * @remark		    : 参见接口类方法说明
	 * @history		    : 
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	public void flushItem(HttpServletRequest request,User item){
        // 先查询对象是否存在
        User oldItem = null;
        String userName = item.getUserName();
        oldItem = userDao.selectItemByUserName(userName);

        if (oldItem == null){
            // 对象不存在，则新增
            addItem(request,item);
        }else{
            // 对象已存在，则修改
            // 设置key值
            item.setUserId(oldItem.getUserId());
            // 只修改非默认值的字段值
            User newItem = new User();
            List<String> fieldNameList = ReflectUtil.getValueFiledNames(item, newItem);
            boolean bSame = ReflectUtil.hasSameSubPropValues(item,oldItem,fieldNameList);
            if (!bSame) {
                // 如果与原对象有属性值不同，则修改记录
                Map<String,Object> params = ReflectUtil.getValuesMap(item,fieldNameList);
                editItem(request,params);
            }
        }
    }    

	/**
	 * 
	 * @methodName		: importExcelFile
	 * @description		: 导入用户对象数据Excel文件
	 * @remark		    : 参见接口类方法说明
	 * @history			:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	public List<String> importExcelFile(HttpServletRequest request,
			MultipartFile upfile, Map<String, Object> params){                
		// 输入参数校验
		checkValidForParams(request, "importExcelFile", params);
		if (upfile == null) {
			throw new BaseException(ExceptionCodes.UPLOAD_NULL_FILE);
		}	

        // 获取参数值
        Integer orgId = (Integer)params.get("orgId");

        // 检查参照ID的有效性
        Orgnization orgnization = (Orgnization)ics.getObjById("Orgnization",orgId);

        // 检查数据权限
        Map<String,Object> drMap = new HashMap<String,Object>();
        drMap.put("orgId", orgId);
        drs.checkUserDr(request, drMap);                

		
		// 获取文件名
		String fileName = upfile.getOriginalFilename();
		// 文件输入流
		InputStream in = null;
		// 文件导入过程中产生的错误信息列表
		List<String> errorList = null;
		// 读取Excel文件得到的数据行列表
		List<String[]> dataRows = null;
		// 文件导入产生的用户对象列表
		List<User> itemList = null;
		
		try {
			try {
				in = upfile.getInputStream();
			} catch(Exception e) {
				LogUtil.error(e);
				throw new BaseException(ExceptionCodes.UPLOAD_READFILE_FAILED,e.getMessage());
			}
			
			// Excel文件导入处理类
			ExcelImportHandler excelImportHandler = new ExcelImportHandler();
			// 数据导入对象基类，注意: new必须加上{}，这样可以访问匿名内部类
			BaseImportObj<User> impObj = new BaseImportObj<User>() {};
			errorList = impObj.getErrorLogList();
			
			// 设置导入字段定义对象列表
			List<ImpExpFieldDef> fieldList = new ArrayList<ImpExpFieldDef>();
			fieldList.add(new ImpExpFieldDef("userName", "用户名", 1));
			fieldList.add(new ImpExpFieldDef("password", "用户密码", 1));
			fieldList.add(new ImpExpFieldDef("userType", "用户类型", 1));
			fieldList.add(new ImpExpFieldDef("phoneNumber", "手机号码", 1));
			fieldList.add(new ImpExpFieldDef("realName", "真实姓名", 1));
			fieldList.add(new ImpExpFieldDef("email", "Email", 0));
			fieldList.add(new ImpExpFieldDef("sex", "性别", 1));
			fieldList.add(new ImpExpFieldDef("birth", "生日", 0));
			impObj.setFieldList(fieldList);
			
			// 读取Excel文件Sheet1，一次性读入数据
			dataRows = excelImportHandler.importFile(in, fileName, impObj.getTitleRowNums(), 0);          
			
			// 导入字段翻译
			SysParameter spItem = null;
            // 因为导入表格不限定各字段的列序号，因此需要根据标题行确定枚举字段列序号
			String[] titles = dataRows.get(0);
            Map<String,Integer> idxMap = new HashMap<String,Integer>();
			for(int i = 0; i < titles.length; i++) {
				String title = titles[i];
				if (title.equals("用户类型")) {
                    idxMap.put("user_type",i);
					continue;
				}

				if (title.equals("性别")) {
                    idxMap.put("sex",i);
					continue;
				}

			}
            for(int i = dataRows.size() -1; i >= 1; i--) {
                String[] dataRow = dataRows.get(i);
                String dataCell = "";
                boolean bError = false;
                for(String classKey : idxMap.keySet()){
                    Integer colIdx = idxMap.get(classKey);
                    dataCell = dataRow[colIdx].trim();
                    if (!dataCell.isEmpty()){
                        spItem = sps.getItemByValue(classKey, dataCell);
                        if (spItem != null) {
                            dataRow[colIdx] = spItem.getItemKey();						
                        }else{
                            // 枚举值错误
                            String error = String.format("row[%d]col[%d]：未定义的枚举值:%s",i,colIdx,dataCell);
                            errorList.add(error);
                            bError = true;
                            break;
                        }                    
                    }
                }
                if (bError) {
                    // 移除错误数据行
                    dataRows.remove(i);
                }
            }
			
			// 导入数据行，一次性导入全部数据
			try {
				itemList = impObj.importAllDatas(dataRows);
			}catch(Exception e) {
				errorList.add(e.getMessage());
			}			
			// 汇总异常信息列表，读取阶段的异常日志放置在前部位置
			impObj.insertErrorList(excelImportHandler.getErrorLog());
			if (errorList.size() > 0) {
				return errorList;
			}	

			// 下面进行数据入库操作
            String operatorName = getUserName(request);
			// 先设置固定参数值
            for (User item : itemList) {
                item.setOrgId(orgId);
		        item.setOperatorName(operatorName);
            }

            // 更新导入
            for (int i = 0; i < itemList.size(); i++) {
                User item = itemList.get(i);
                try{
                    flushItem(request,item);
                }catch(Exception e) {
				    errorList.add(impObj.getObj2RowNoMap().get(item) + ":" + e.getMessage());
			    }	
            }

			// 最后输出异常信息列表
			return errorList;
		} catch(Exception e) {
			// 传递异常
			throw new RuntimeException(e);
		} finally {
			// 关闭in文件流
			FileUtil.closeStream(in);
		}
    }            

	/**
	 * 
	 * @methodName		: exportExcelFile
	 * @description	    : 根据查询条件导出用户对象数据Excel文件
	 * @remark		    : 参见接口类方法说明
     * @history		:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	public void exportExcelFile(HttpServletRequest request,HttpServletResponse response,
			Map<String,Object> params){

	    List<User> itemList = null;
		
        // 数据权限控制
        List<Integer> orgIdList = drs.getQueryDrList(request,"orgId");
        params.put("orgIdList",orgIdList);
            
		
		// 根据查询条件params，查询数据库，获取用户对象列表
		itemList = userDao.selectItems(params);
		if (itemList.size() == 0) {
			throw new BaseException(ExceptionCodes.EXPORT_FILE_NO_DATA);
		}	
        fillRefValue(itemList);
		
		// 构造导出标题列表
		List<ImpExpFieldDef> fieldList = new ArrayList<ImpExpFieldDef>();
		fieldList.add(new ImpExpFieldDef("userId","用户ID",0));
		fieldList.add(new ImpExpFieldDef("userName","用户名",0));
		fieldList.add(new ImpExpFieldDef("userType","用户类型",0));
		fieldList.add(new ImpExpFieldDef("orgId","组织机构ID",0));
		fieldList.add(new ImpExpFieldDef("orgName","组织机构名称",0));
		fieldList.add(new ImpExpFieldDef("realName","真实姓名",0));
		fieldList.add(new ImpExpFieldDef("email","Email",0));
		fieldList.add(new ImpExpFieldDef("phoneNumber","手机号码",0));
		fieldList.add(new ImpExpFieldDef("sex","性别",0));
		fieldList.add(new ImpExpFieldDef("birth","生日",0));

		// 使用导出类
		BaseExportObj expObj = new BaseExportObj();
		// 设置标题数据
		expObj.setTitles(fieldList);
		// 输出标题行
		String[] arrTitles = expObj.exportTitleList();
		// 输出导出数据行
		List<String[]> dataRowList = expObj.exportDataList(itemList);
		
		// 进行字段值翻译
		String trans = "";
		SysParameter spItem = null;
        String itemValue = "";
		for(String[] dataRow : dataRowList) {
            itemValue = dataRow[2];
            spItem = sps.getItemByKey("user_type", itemValue, false);
			if (spItem != null) {
				trans = spItem.getItemValue();							
			}else {
				trans = "";
			}
			dataRow[2] = trans;

            itemValue = dataRow[8];
            spItem = sps.getItemByKey("sex", itemValue, false);
			if (spItem != null) {
				trans = spItem.getItemValue();							
			}else {
				trans = "";
			}
			dataRow[8] = trans;

		}
		
		// 导出处理
		// 使用Excel导出处理类
		ExcelExportHandler excelExpHandler = new ExcelExportHandler();
		// 临时文件路径，文件名随机
		String filename = RandomStringUtils.randomAlphanumeric(16) + ".xlsx";
		String excelFilePath = uploadConfig.getUploadPath() + "/" + filename;
		String sheetName = "用户记录数据";
        // 导出文件的文件名
        String expFilename = sheetName + ".xlsx";
		try {
			// 生成excel临时文件
			excelExpHandler.exportExcelFile(arrTitles, dataRowList, excelFilePath, sheetName);
			// 调用基类下载方法
			FileUtil.download(response, excelFilePath, expFilename, "application/octet-stream");
		}catch(Exception e) {
			LogUtil.error(e);
			throw new BaseException(ExceptionCodes.EXPORT_EXCEL_FILE_FAILED,e.getMessage());
		}finally {
			if (!debug) {
				// 删除临时文件
				FileUtil.deleteFile(excelFilePath);
			}
		}                

    }

	/**
	 * @methodName			: checkValidForParams
	 * @description			: 输入参数校验
	 * @param request		: request对象
	 * @param methodName	: 方法名称
	 * @param params		: 输入参数
	 * @history				:
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
	@Override
	public void checkValidForParams(HttpServletRequest request, String methodName,
			 Object params) {
		switch(methodName) {
		case "addItem":
		{
			User item = (User)params;
			
			// 检查项: 必选字段
			String[] escapeFields = new String[]{"userType","realName","email","phoneNumber",
	            	"sex","idNo","openId","woaOpenid","remark"};  
            ReflectUtil.checkMandatoryFields(item,mandatoryFieldList,escapeFields);
            
            // 用户名格式校验
            ValidateUtil.loginNameValidator("userName", item.getUserName());
            
            // 手机号码格式校验
            if (!item.getPhoneNumber().isEmpty()) {
            	ValidateUtil.phoneNumberValidator("phoneNumber", item.getPhoneNumber());
            }

            // email格式校验
            if (!item.getEmail().isEmpty()) {
                ValidateUtil.emailValidator("email", item.getEmail());            	
            }            
		}
		break;
        case "addItems":
		{
			List<User> itemList = (List<User>)params;
			
			// 检查项: 必选字段
			String[] escapeFields = new String[]{"userType","realName","email","phoneNumber",
	            	"sex","idNo","openId","woaOpenid","remark"};  
            for(User item : itemList){
                ReflectUtil.checkMandatoryFields(item,mandatoryFieldList,escapeFields);
                
                // 用户名格式校验
                ValidateUtil.loginNameValidator("userName", item.getUserName());
                
                // 手机号码格式校验
                if (!item.getPhoneNumber().isEmpty()) {
                	ValidateUtil.phoneNumberValidator("phoneNumber", item.getPhoneNumber());
                }

                // email格式校验
                if (!item.getEmail().isEmpty()) {
                    ValidateUtil.emailValidator("email", item.getEmail());            	
                }                 
            }
		}        
        break;
		case "editItem":
		{
			Map<String,Object> map = (Map<String,Object>)params;
			
			// 检查项: 
            // 必选字段：key
			Utility.checkKeyFields(map,new String[] {"userId"});

            // 可选字段：至少一个修改字段
            String[] optFields = new String[] {"userName","userType","orgId","realName","email",
            	"phoneNumber","sex","birth","idNo","openId","woaOpenid","remark"};                
            Utility.checkOpKeyFields(map,optFields); 
            
            // 用户名格式校验
            String userName = (String)map.get("userName");
            if (userName != null && !userName.isEmpty()) {
                ValidateUtil.loginNameValidator("userName", userName);            	
            }
            
            // 手机号码格式校验
            String phoneNumber = (String)map.get("phoneNumber");
            if (phoneNumber != null && !phoneNumber.isEmpty()) {
                ValidateUtil.phoneNumberValidator("phoneNumber", phoneNumber);            	
            }
            
            // email格式校验
            String email = (String)map.get("email");
            if (email != null && !email.isEmpty()) {
                ValidateUtil.emailValidator("email", email);            	
            }            
		}
		break;
		case "updateItems":
		{
			Map<String,Object> map = (Map<String,Object>)params;
			
			// 检查项: 
            // 可选字段：至少一个修改字段
			Utility.checkOpKeyFields(map,new String[] {"orgId","userType","deleteFlag",
				"operatorName"});
            // 可选字段：至少一个条件字段
			Utility.checkOpKeyFields(map,new String[] {"userIdList","userName","phoneNumber"});
		}
		break;
		case "deleteItem":
		{
			Map<String,Object> map = (Map<String,Object>)params;
			
			// 检查项: 
            // 必选字段：key
			Utility.checkKeyFields(map,new String[] {"userId"});
		}
		break;
		case "getItem":
		{
			Map<String,Object> map = (Map<String,Object>)params;
			
			// 检查项: 
            // 必选字段：key
			Utility.checkKeyFields(map,new String[] {"userId"});
		}
		break;
		case "importExcelFile":
		{
			Map<String,Object> map = (Map<String,Object>)params;
			
			// 检查项: 
            // 必选字段：约定导入参数字段
			Utility.checkKeyFields(map,new String[] {"orgId"});
		}
		break;        
		default:
			break;
		}
	}

	/**
	 * 
	 * @methodName		: checkUniqueByUserName
	 * @description	    : 检查userName属性值的唯一性
     * @param userName	: 用户名
	 * @history		    : 
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
    private void checkUniqueByUserName(String userName) {
        User item = userDao.selectItemByUserName(userName);
        if (item != null) {
            // 如果唯一键对象已存在
            throw new BaseException(ExceptionCodes.OBJECT_ALREADY_EXISTS,"userName=" + userName);            
        }
    }

	/**
	 * 
	 * @methodName		: checkUniqueByPhoneNumber
	 * @description	    : 检查phoneNumber属性值的唯一性
     * @param phoneNumber	: 手机号码
	 * @history		    : 
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
    private void checkUniqueByPhoneNumber(String phoneNumber) {
        if (phoneNumber.equals("")) {
            // 如果为例外值
            return;
        }

        User item = userDao.selectItemByPhoneNumber(phoneNumber);
        if (item != null) {
            // 如果唯一键对象已存在
            throw new BaseException(ExceptionCodes.OBJECT_ALREADY_EXISTS,
            	"phoneNumber=" + phoneNumber);            
        }
    }

	/**
	 * 
	 * @methodName		: checkUniqueByIdNo
	 * @description	    : 检查idNo属性值的唯一性
     * @param idNo	: 身份证号码
	 * @history		    : 
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
    private void checkUniqueByIdNo(String idNo) {
        if (idNo.equals("")) {
            // 如果为例外值
            return;
        }

        User item = userDao.selectItemByIdNo(idNo);
        if (item != null) {
            // 如果唯一键对象已存在
            throw new BaseException(ExceptionCodes.OBJECT_ALREADY_EXISTS,"idNo=" + idNo);            
        }
    }

	/**
	 * 
	 * @methodName		: checkUniqueByOpenId
	 * @description	    : 检查openId属性值的唯一性
     * @param openId: 微信小程序的openid
	 * @history		    : 
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
    private void checkUniqueByOpenId(String openId) {
        if (openId.equals("")) {
            // 如果为例外值
            return;
        }

        User item = userDao.selectItemByOpenId(openId);
        if (item != null) {
            // 如果唯一键对象已存在
            throw new BaseException(ExceptionCodes.OBJECT_ALREADY_EXISTS,"openId=" + openId);            
        }
    }

	/**
	 * 
	 * @methodName		: checkUniqueByWoaOpenid
	 * @description	    : 检查woaOpenid属性值的唯一性
     * @param woaOpenid	: 微信公众号openid
	 * @history		    : 
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
    private void checkUniqueByWoaOpenid(String woaOpenid) {
        if (woaOpenid.equals("")) {
            // 如果为例外值
            return;
        }

        User item = userDao.selectItemByWoaOpenid(woaOpenid);
        if (item != null) {
            // 如果唯一键对象已存在
            throw new BaseException(ExceptionCodes.OBJECT_ALREADY_EXISTS,"woaOpenid=" + woaOpenid);            
        }
    }

	/**
	 * 
	 * @methodName		: fillRefValue
	 * @description	    : 设置用户对象的引用属性值
     * @param item      : 用户对象
	 * @history		    : 
	 * ------------------------------------------------------------------------------
	 * date			version		modifier		remarks                   
	 * ------------------------------------------------------------------------------
	 * 2023/05/17	1.0.0		sheng.zheng		初版
	 *
	 */
    @Override
    public <T> void fillRefValue(T item2) {
    	User item = (User)item2;
        try{
            Integer orgId = item.getOrgId();
            Orgnization orgnization = (Orgnization)ics.getObjById("Orgnization",orgId);                        
            item.setOrgName(orgnization.getOrgName());
        }catch(Exception e) {
            // pass
        }

    }

}